package com.xb.loan.util.qrtz.jmx;


import com.j256.simplejmx.common.JmxOperation;
import com.j256.simplejmx.common.JmxResource;
import com.xb.loan.util.DateHelper;
import com.xb.loan.util.StringUtils;
import com.xb.loan.util.json.JsonUtils;
import com.xb.loan.util.qrtz.TaskScheduleManager;
import com.xb.loan.util.qrtz.common.bean.TaskEntity;
import com.xb.loan.util.qrtz.common.store.TaskEntiryStoreSupport;
import com.xb.loan.util.qrtz.task.AbstractCronTask;
import com.xb.loan.util.qrtz.task.AbstractSimpleTask;
import com.xb.loan.util.qrtz.task.AbstractTask;
import com.xb.loan.util.qrtz.task.Task;
import com.xb.loan.util.qrtz.common.Constants;
import org.quartz.DateBuilder;
import org.quartz.JobExecutionContext;
import org.quartz.SchedulerException;
import org.quartz.TriggerKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.ParseException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

/**
 * 
 * jmx
 * @author hyd
 */
@JmxResource(domainName = "com.genlot.util.schedule.quartz.jmx", beanName = "TaskScheduleJmxSupport", description = "TaskScheduleJmxSupport")
public class TaskScheduleJmxSupport {
    
    private Logger logger = LoggerFactory.getLogger(TaskScheduleJmxSupport.class);
    private TaskScheduleManager taskScheduleManager;
    private String defaultGroup = "default";
    private TaskEntiryStoreSupport taskEntityStoreSupport;
    
    private static  String optType_add="add"; 
    private static  String optType_edit="edit"; 
    
    public TaskEntiryStoreSupport getTaskEntityStoreSupport() {
        return taskEntityStoreSupport;
    }

    public void setTaskEntityStoreSupport(TaskEntiryStoreSupport taskEntityStoreSupport) {
        this.taskEntityStoreSupport = taskEntityStoreSupport;
    }

    public TaskScheduleManager getTaskScheduleManager() {
        return taskScheduleManager;
    }

    public void setTaskScheduleManager(TaskScheduleManager taskScheduleManager) {
        this.taskScheduleManager = taskScheduleManager;
    }

    /**
     *  调度计划任务
     * */
    @JmxOperation(description = "sheduleCronTask", parameterNames = { "taskName", "cron", "classzz", "taskDate","optType","gameId","issueId" }, parameterDescriptions = { "" })
    public void sheduleCronTask(String taskName, String cron, String classzz, String taskDate, String optType,String gameId,String issueId) {
        
        if(cron == null || "".equals(cron))
            return;
        String taskId = taskName + "$" + defaultGroup;
        TaskEntity taskEntity = taskEntityStoreSupport.getTaskEntity(taskId);
        if (optType_add.equals(optType)) {
            if (taskEntity == null) {
                if(!checkClassIsExists(classzz))
                    return ;
                TaskEntity newTaskEntity = new TaskEntity();
                newTaskEntity.setId(taskId);
                newTaskEntity.setClassName(classzz);
                newTaskEntity.setCron(cron);
                if (taskDate != null && !"".equals(taskDate)) {
                    newTaskEntity.setTask_date(JsonUtils.fromJson(taskDate, HashMap.class));
                }
                try {
                    Task newTask = buildTask(newTaskEntity);
                    if (newTask instanceof AbstractCronTask) {
                        ((AbstractCronTask) newTask).setGame_id(gameId);
                        ((AbstractCronTask) newTask).setIssue_id(issueId);
                        getTaskScheduleManager().shedule(newTask);
                    }
                } catch (Exception e) {
                    logger.error("", e);
                }
            }
        } else {
            if (taskEntity == null) return;
            try {
                Task taskTask = buildTask(taskEntity);
                String newTaskData = taskDate;
                if (newTaskData == null || "".equals(newTaskData)) {
                    newTaskData = "{}";
                } else {
                    ((AbstractCronTask) taskTask).setParams(JsonUtils.fromJson(newTaskData, HashMap.class));
                }

                taskEntityStoreSupport.updateTaskEntiryForCronAndData(taskId, Constants.Status.WAITING.toString(), cron, newTaskData);
                ((AbstractCronTask) taskTask).setCron_expression(cron);
                getTaskScheduleManager().reShedule(taskTask);
            } catch (Exception e) {
                logger.error("", e);
            }

        }

    }
    

    /**
     *  调度简单任务
     * */
    @JmxOperation(description = "sheduleSimpleTask", parameterNames = { "taskName", "delayTime", "classzz", "taskDate" ,"optType","gameId","issueId"}, parameterDescriptions = { "" })
    public void sheduleSimpleTask(String taskName, String delayTime, String classzz, String taskDate, String optType,String gameId,String issueId) {

        String taskId = taskName + "$" + defaultGroup;
        TaskEntity taskEntity = taskEntityStoreSupport.getTaskEntity(taskId);
        if (optType_add.equals(optType)) {
            if (taskEntity == null) {
                if(!checkClassIsExists(classzz))
                    return ;
                TaskEntity newTaskEntity = new TaskEntity();
                newTaskEntity.setId(taskId);
                newTaskEntity.setClassName(classzz);
                if (delayTime != null && !"".equals(delayTime)) {
                    try {
                        newTaskEntity.setFireTime(DateHelper.convertToDate("yyyy-MM-dd HH:mm:ss", delayTime).getTime()+"");
                    } catch (ParseException e) {
                        logger.error("", e);
                        return;
                    }
                }
                if (taskDate != null && !"".equals(taskDate)) {
                    newTaskEntity.setTask_date(JsonUtils.fromJson(taskDate, HashMap.class));
                }
                try {
                    Task newTask = buildTask(newTaskEntity);
                    if (newTask instanceof AbstractSimpleTask) {
                        ((AbstractSimpleTask)newTask).setGame_id(gameId);
                        ((AbstractSimpleTask)newTask).setIssue_id(issueId);
                        getTaskScheduleManager().shedule(newTask);
                    }
                } catch (Exception e) {
                    logger.error("", e);
                }
            }
        } else {
            if (taskEntity == null) return;
            try {

                Task taskTask = buildTask(taskEntity);
                Date nextDate = null;
                try {
                    if (delayTime != null && !"".equals(delayTime)) {
                        nextDate = DateHelper.convertToDate("yyyy-MM-dd HH:mm:ss", delayTime);
                    }
                } catch (ParseException e) {
                    logger.error("", e);
                    return;
                }

                String newTaskData = taskDate;
                if (newTaskData == null || "".equals(newTaskData)) {
                    newTaskData = "{}";
                } else {
                    ((AbstractSimpleTask) taskTask).setParams(JsonUtils.fromJson(newTaskData, HashMap.class));
                }
                ((AbstractSimpleTask) taskTask).setStartTime(nextDate);

                Long fireTime = (nextDate == null ? nextDate.getTime() : DateBuilder.nextGivenSecondDate(null, 2).getTime());

                taskEntityStoreSupport.updateTaskEntiryForDelayTimeAndData(taskId, Constants.Status.WAITING.toString(), fireTime, newTaskData);
                getTaskScheduleManager().reShedule(taskTask);
            } catch (Exception e) {
                logger.error("", e);
            }

        }

    }

    
    /**
     *  重新调度任务
     * */
    @JmxOperation(description = "resumeSheduleTask", parameterNames = { "taskName" }, parameterDescriptions = { "" })
    public void resumeSheduleTask(String taskName) {
        String taskId = taskName + "$" + defaultGroup;
        try {
            TaskEntity taskEntity = taskEntityStoreSupport.getTaskEntity(taskId);
            if (taskEntity == null)
                return;
            if (Constants.Status.COMPLETE.toString().equals(taskEntity.getTask_status())) {
                taskEntityStoreSupport.updateTaskEntiryForStatus(taskId, Constants.Status.WAITING.toString());
            }
            
            Task task = buildTask(taskEntity);
            getTaskScheduleManager().reShedule(task);

        } catch (Exception e) {
            logger.error("", e);
        }
    }
    
    private boolean checkClassIsExists(String className) {
        try {
            Class.forName(className);
        } catch (ClassNotFoundException e) {
            logger.info("Class not found calssName=" + className);
            return false;
        }
        return true;
    }

    private Task buildTask(TaskEntity taskEntity) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        Object obj = getClass().forName(taskEntity.getClassName()).newInstance();
        if (!(obj instanceof AbstractTask))
            return null;
        AbstractTask temp = (AbstractTask) obj;
        temp.setJobName(StringUtils.paser(taskEntity.getId(), "$")[0]);
        temp.setParams(taskEntity.getTask_date());

        if (obj instanceof AbstractCronTask) {
            AbstractCronTask tempObj = (AbstractCronTask) temp;
            if (taskEntity.getCron() == null || "".equals(taskEntity.getCron())) 
                return null;
            tempObj.setCron_expression(taskEntity.getCron());
        } else if (obj instanceof AbstractSimpleTask) {
            AbstractSimpleTask tempObj = (AbstractSimpleTask) temp;
            String fire_time = taskEntity.getFireTime();
            if (fire_time != null && !"".equals(fire_time)) {
                try {
                    tempObj.setStartTime(new Date(Long.parseLong(fire_time)));
                } catch (Exception e) {
                    logger.error("", e);
                }
            }
        }
        return temp;
    }
    
    /**
     *  暂停触发器
     * */
    @JmxOperation(description = "pauseTrigger", parameterNames = { "taskName" }, parameterDescriptions = { "" })
    public void pauseTrigger(String taskName) {
        TriggerKey triggerKey = TriggerKey.triggerKey(taskName, defaultGroup);
        try {
            taskScheduleManager.getStdScheduler().pauseTrigger(triggerKey);
        } catch (SchedulerException e) {
            logger.error("", e);
        }
    }
    
    /**
     *  恢复触发器
     * */
    @JmxOperation(description = "resumeTrigger", parameterNames = { "taskName" }, parameterDescriptions = { "" })
    public void resumeTrigger(String taskName) {
        TriggerKey triggerKey = TriggerKey.triggerKey(taskName, defaultGroup);
        try {
            taskScheduleManager.getStdScheduler().resumeTrigger(triggerKey);
        } catch (SchedulerException e) {
            logger.error("", e);
        }
    }
    
    /**
     *  移除触发器
     * */
    @JmxOperation(description = "removeTrigdger", parameterNames = { "taskName"}, parameterDescriptions = { "" })
    public void removeTrigdger(String taskName) {
        TriggerKey triggerKey = TriggerKey.triggerKey(taskName, defaultGroup);
        try {
            taskScheduleManager.getStdScheduler().pauseTrigger(triggerKey);
            taskScheduleManager.getStdScheduler().unscheduleJob(triggerKey);
        } catch (SchedulerException e) {
            logger.error("", e);
        }
    }
    
    
    /**
     *  获取实例配置的线程数
     * */
    @JmxOperation(description = "getThreadPoolSize", parameterNames = {}, parameterDescriptions = { "" })
    public int queryThreadPoolSize() {
        return taskScheduleManager.getStdScheduler().getMetaData().getThreadPoolSize();
    }
    
    /**
     *  监控线程状态
     * */
    @JmxOperation(description = "queryThreadState", parameterDescriptions = { "" })
    public int[] queryThreadState() {
    	int[] tse = new int[3];
        try {
        	//Quartz总线程数
        	tse[0] = queryThreadPoolSize();
        	//Quartz执行线程数
        	tse[1] = 0;
        	List<JobExecutionContext> jobList = taskScheduleManager.getStdScheduler().getCurrentlyExecutingJobs();
        	if(jobList != null){
        		//Quartz执行任务数
        		tse[2] = jobList.size();
        	}else{
        		tse[2] = 0;
        	}
        } catch (Exception e) {
            logger.error("", e);
        }
        return tse;
    }
}
